package com.zhoug.player3.vlx;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.TextureView;


import com.zhoug.common3.Logger;

import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;

/**
 * @Author: zhoug
 * @Date: 2024-06-22
 * @Description:
 */
public class VLCPlayer {

    private static final String TAG = ">>>VLCPlayer";
    /**
     * 播放器处于初始状态,
     */
    public static final int IDLE = 0;
    /**
     * 开始播放
     */
    public static final  int START = 1;
    /**
     * 资源准备好了
     */
    public static final  int PREPARED = 2;
    /**
     * 正在播放
     */
    public static final  int PLAYING = 3;
    /**
     * 暂停播放
     */
    public static final  int PAUSE = 4;
    /**
     * 停止播放
     */
    public static final int STOP = 5;
    /**
     * 播放完成了
     */
    public static final int ENDED = 6;

    /**
     * 播放状态
     */
    @Documented
    @Retention(RetentionPolicy.SOURCE)
    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
    @IntDef({IDLE, START, PREPARED, PLAYING, PAUSE, STOP, ENDED})
    @interface State {
    }
    private static final int EVENT_PLAY = 101;//开始
    private static final int EVENT_PAUSE = 102;//暂停
    private static final int EVENT_STOP = 103;//停止
    private static final int EVENT_RELEASE = 104;//释放资源

    private LibVLC mLibVLC;
    private MediaPlayer mPlayer;
    private VLCPlayerCallback callback;

    private int mWidth;
    private int mHeight;
    //播放线程
    private HandlerThread mPlayThread = new HandlerThread("PlayThread1");
    private Handler mPlayHandler;
    private boolean mRelease = false;//标记释放资源
    protected boolean mMute = true;//默认静音
    protected int mPlayState = IDLE;

    public VLCPlayer(Context context, ArrayList<String> options) {
        mLibVLC = new LibVLC(context, options);
        mPlayer = new MediaPlayer(mLibVLC);
        mPlayer.setEventListener(eventListener);
        mPlayThread.start();
        mPlayHandler = new Handler(mPlayThread.getLooper(), mPlayEventCallback);
    }

    public VLCPlayer(Context context) {
        this(context, getDefOptions());
    }

    /**
     * 处理播放事件
     */
    private Handler.Callback mPlayEventCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            try {
                if (msg.what == EVENT_RELEASE) {
                    mPlayer.release();
                    mPlayer = null;
                    mLibVLC = null;
                    mPlayThread.quit();
                    Logger.d(TAG, "资源释放成功");
                } else {
                    if (isReleased()) return true;
                    switch (msg.what) {
                        case EVENT_PLAY:
                            mPlayer.play();
                            break;
                        case EVENT_PAUSE:
                            mPlayer.pause();
                            break;
                        case EVENT_STOP:
                            mPlayer.stop();
                            break;

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
    };

    private void sendPlayEvent(int event) {
        Message msg = mPlayHandler.obtainMessage();
        msg.what = event;
        mPlayHandler.sendMessage(msg);
    }

    private void removePlayEvent(int event) {
        mPlayHandler.removeMessages(event);
    }

    private void removeAllPlayEvent() {
        mPlayHandler.removeMessages(EVENT_PLAY);
        mPlayHandler.removeMessages(EVENT_PAUSE);
        mPlayHandler.removeMessages(EVENT_STOP);
        mPlayHandler.removeMessages(EVENT_RELEASE);
    }

    private void removePlayEvents(int... event) {
        if (event == null) return;
        for (int j : event) {
            removePlayEvent(j);
        }
    }

    /**
     * 播放监听
     */
    private MediaPlayer.EventListener eventListener = new MediaPlayer.EventListener() {
        @Override
        public void onEvent(MediaPlayer.Event event) {
            switch (event.type) {
                case MediaPlayer.Event.Opening:
                    Logger.d(TAG, "onEvent:Opening");
                    if (mPlayState != START ) {
                        mPlayState=START;
                        if(callback!=null){
                            callback.onStart();
                        }
                    }
                    break;
                case MediaPlayer.Event.Buffering:
                    // 处理缓冲事件
                    float buffering = event.getBuffering();
                    if (callback != null) {
                        callback.onBuffering(buffering);
                    }
                    if (buffering>=100 && mPlayState != PLAYING ) {
                        mPlayState=PLAYING;
                        if(callback!=null){
                            callback.onPlaying();
                        }
                    }
                    break;
                case MediaPlayer.Event.Playing:
                    Logger.d(TAG, "播放成功,可能由于缓冲会等很久才显示画面");
                    setMute(mMute);
//                    if (mPlayState != PLAYING && callback != null) {
//                        callback.onPlaying();
//                    }
                    break;
                case MediaPlayer.Event.Paused:
                    Logger.d(TAG, "暂停");
                    if (mPlayState != PAUSE) {
                        mPlayState=PAUSE;
                        if(callback!=null){
                            callback.onPaused();
                        }
                    }
                    break;
                case MediaPlayer.Event.Stopped:
                    Logger.d(TAG, "停止");
                    if (mPlayState != STOP) {
                        mPlayState=STOP;
                        if(callback!=null){
                            callback.onStopped();
                        }
                    }
                    break;
                case MediaPlayer.Event.EndReached:
                    // 处理播放结束事件
                    Logger.d(TAG, "处理播放结束事件");
                    if (mPlayState != ENDED) {
                        mPlayState=ENDED;
                        if(callback!=null){
                            callback.onEndReached();
                        }
                    }
                    break;
                case MediaPlayer.Event.EncounteredError:
                    // 处理播放错误事件
                    if (callback != null) {
                        callback.onError();
                    }
                    break;
                case MediaPlayer.Event.LengthChanged:
                    if (callback != null) {
                        //long duration = mMediaPlayer.getMedia().getDuration();
                        callback.onTotalTime(mPlayer.getLength());
                    }
                    break;
                case MediaPlayer.Event.TimeChanged:
                    // 处理播放进度变化事件
                    if (callback != null) {
                        callback.onTimeChanged(event.getTimeChanged());
                    }
                    break;
                case MediaPlayer.Event.PositionChanged:
                    // 处理播放位置变化事件
                    if (callback != null) {
                        callback.onPositionChanged(event.getPositionChanged());
                    }
                    break;
                case MediaPlayer.Event.Vout:
                    //在视频开始播放之前，视频的宽度和高度可能还没有被确定，
                    // 因此我们需要在MediaPlayer.Event.Vout事件发生后才能获取到正确的宽度和高度
//                    IMedia.VideoTrack vtrack = (IMedia.VideoTrack) mMediaPlayer.getSelectedTrack(Media.Track.Type.Video);

                    break;

                case MediaPlayer.Event.RecordChanged:
                    Logger.d(TAG, "录像状态改变");
                    break;
                default:
                    Logger.d(TAG, "event.type:" + event.type);
            }

        }
    };


    public void setVideoSurface( TextureView textureView) {
        if (isReleased()) return;
        Logger.d(TAG, "mTextureView:" + textureView);
        if (textureView != null) {
            textureView.setKeepScreenOn(true);
            setVideoSurface(textureView.getSurfaceTexture());
            setWindowSize(textureView.getWidth(), textureView.getHeight());
            textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
                @Override
                public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                    Logger.d(TAG, "onSurfaceTextureAvailable");
                    setVideoSurface(surface);
                    setWindowSize(width, height);

                }

                @Override
                public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

                }

                @Override
                public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                    detachViews();
                    return false;
                }

                @Override
                public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

                }
            });
            textureView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                if (isReleased()) {
                    return;
                }
                // 获取新的宽度和高度
                int w = right - left;
                int h = bottom - top;
                setWindowSize(w, h);
            });
        } else {
            detachViews();
        }
    }

    /**
     * 设置 SurfaceTexture
     */
    private void detachViews() {
        if (isReleased()) {
            return;
        }
        mPlayer.getVLCVout().detachViews();
    }

    /**
     * 设置 SurfaceTexture
     *
     * @param videoSurfaceTexture SurfaceTexture
     */
    private void setVideoSurface(SurfaceTexture videoSurfaceTexture) {
        if (isReleased() || videoSurfaceTexture == null) {
            return;
        }
        mPlayer.getVLCVout().setVideoSurface(videoSurfaceTexture);
        mPlayer.getVLCVout().attachViews();
    }


    /**
     * 设置播放窗口大小
     *
     * @param width
     * @param height
     */
    public void setWindowSize(int width, int height) {
        if (isReleased()) {
            return;
        }
        // 设置VLC播放器的宽高参数
        if (width > 0 && height > 0) {
            mWidth = width;
            mHeight = height;
            mPlayer.getVLCVout().setWindowSize(mWidth, mHeight);
            //下面2行代码 设置充满屏幕否则有黑边
            mPlayer.setAspectRatio(mWidth+":"+mHeight);
            mPlayer.setScale(0);
        }
        Logger.d(TAG, "Window mWidth=" + mWidth + ",mHeight=" + mHeight);

    }

    /**
     * 设置播放地址
     *
     * @param url
     */
    public void setDataSource(String url) {
        if (mPlayer == null) return;
        try {
            Media media = new Media(mLibVLC, Uri.parse(url));
            mPlayer.setMedia(media);
        } catch (Exception e) {
            Log.e("VLCPlayer", e.getMessage(), e);
        }
    }

    /**
     * 播放
     */
    public void play() {
        if (isReleased()) {
            return;
        }
        mPlayState=START;
        if(callback!=null){
            callback.onStart();
        }
        sendPlayEvent(EVENT_PLAY);
    }

    /**
     * 暂停
     */
    public void pause() {
        if (isReleased()) {
            return;
        }
        if (mPlayer.isPlaying() || mPlayState == PREPARED || mPlayState == PLAYING || mPlayState == START) {
            Logger.d(TAG, "pausePlay");
            mPlayState=PAUSE;
            if(callback!=null){
                callback.onPaused();
            }
            removeAllPlayEvent();
            sendPlayEvent(EVENT_PAUSE);
        }
    }



    /**
     * 停止播放
     */
    public void stop() {
        if (isReleased()) {
            return;
        }
        if (mPlayer.isPlaying() || mPlayState == PREPARED || mPlayState == PLAYING ||
                mPlayState == PAUSE || mPlayState == START || mPlayState == ENDED) {
            Logger.d(TAG, "stopPlay");
            mPlayState=STOP;
            if(callback!=null){
                callback.onStopped();
            }
            removeAllPlayEvent();
            sendPlayEvent(EVENT_STOP);
        }
    }

    public int setVolume(int volume) {
        if (mPlayer == null) {
            return -1;
        }
        return mPlayer.setVolume(volume);
    }

    public void setMute(boolean mute) {
        if (isReleased()) {
            return;
        }
        this.mMute = mute;
        mPlayer.setVolume(mute ? 0 : 100);
    }


    /**
     * 释放资源
     */
    public void release() {
        if (isReleased()) {
            return;
        }
        Logger.d(TAG, "release");
        mRelease = true;

        removeAllPlayEvent();
        sendPlayEvent(EVENT_RELEASE);

    }

    /**
     * 开始录像
     *
     * @param path 录像储存的文件夹,eg:/storage/emulated/0/视频
     */
    public boolean startRecording(String path) {
        if (mPlayer != null) {
            return mPlayer.record(path);
        }
        return false;
    }

    /**
     * 停止录像
     */
    public boolean stopRecording() {
        if (mPlayer != null) {
            return mPlayer.record(null);
        }
        return false;
    }

    public void seekTo(long time) {
        if (mPlayer != null) {
            mPlayer.setTime(time);
        }
    }
    /**
     * 是否正在播放
     *
     * @return
     */
    public boolean isPlaying() {
        boolean isPlaying = !isReleased() && (mPlayer.isPlaying() || mPlayState == PLAYING);
        Logger.d(TAG, "isPlaying:" + isPlaying);
        return isPlaying;
    }



    /**
     * 判断资源是否已经释放
     *
     * @return
     */
    public boolean isReleased() {
        boolean release = mPlayer == null || mPlayer.isReleased();
        if (release) {
            Logger.d(TAG, "资源已释放");
        } else if (mRelease) {
            Logger.d(TAG, "正在释放资源");
        }
        return release || mRelease;
    }


    public void setCallback(VLCPlayerCallback callback) {
        this.callback = callback;
    }

    public interface VLCPlayerCallback {
        /**
         * 处理缓冲事件
         *
         * @param bufferPercent
         */
        void onBuffering(float bufferPercent);

        /**
         * 开始播放
         */
        void onStart();

        /**
         * 播放成功
         */
        void onPlaying();

        /**
         * 暂停播放
         */
        void onPaused();

        /**
         * 停止播放
         */
        void onStopped();

        /**
         * 播放完成
         */
        void onEndReached();

        /**
         * 播放错误
         */
        void onError();

        /**
         * 视频总时间
         *
         * @param totalTime
         */
        void onTotalTime(long totalTime);

        /**
         * 播放时间
         *
         * @param currentTime 毫秒
         */
        void onTimeChanged(long currentTime);

        /**
         * 播放到总视频长度的占比 0.0-1.0
         *
         * @param position
         */
        void onPositionChanged(float position);
    }

    public static ArrayList<String> getDefOptions() {
//        ArrayList<String> options = new ArrayList<>();
//        options.add("--audio-time-stretch");
//        options.add("-vvv");
//        options.add("--no-drop-late-frames"); //防止掉帧
//        options.add("--no-skip-frames"); //防止掉帧
//        options.add("--rtsp-tcp");//强制使用TCP方式
//        options.add("--avcodec-hw=any"); //尝试使用硬件加速
//        options.add("--live-caching=1000");//缓冲时长
//        return options;
        ArrayList<String> options = new ArrayList<>();
        //缓存
        //--ftp-caching	缓存值 (毫秒)	<整型>
        options.add("--file-caching=1500");//文件缓存
        options.add("--live-caching=1500");//直播缓存
        options.add("--network-caching=1500");//网络缓存
        options.add("--sout-mux-caching=1500");//输出缓存
        options.add("--codec=mediacodec,iomx,all");
        options.add("-vvv");
//        options.add("--http-caching=2000");
//        options.add("--ftp-caching=150");
//        options.add("--sout-udp-caching=150");
//        options.add("--realrtsp-caching=150");
//        options.add("--tcp-caching=150");
//        options.add("--udp-caching=150");
//        options.add("--smb-caching=150");
//        options.add("--mms-caching=150");
        //--http-reconnect, --no-http-reconnect	自动重新连接 (默认关闭)
//        options.add("--http-reconnect");
        //--f, --fullscreen, --no-fullscreen	全屏幕视频输出 (默认关闭)
//        options.add("--fullscreen");
        //--drop-late-frames, --no-drop-late-frames	丢弃晚的帧 (默认打开)
        options.add("--drop-late-frames");
        //--skip-frames, --no-skip-frames	跳过帧 (默认打开)
        options.add("skip-frames");
        options.add("--audio-time-stretch");
        options.add("--rtsp-tcp");//强制使用TCP方式 2000
        options.add("--avcodec-hw=any"); //尝试使用硬件加速
        options.add("--clock-jitter=0");//
//        options.add("--clock-synchro=0");//设置了后直播不能暂停
        return options;
    }


}
